package com.example.yuanboot.common.config.mybatis;

import com.baomidou.mybatisplus.extension.plugins.handler.DataPermissionHandler;
import com.example.yuanboot.common.anno.UserInterception;
import com.example.yuanboot.common.enums.config.DataHandlerEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
import net.sf.jsqlparser.expression.operators.relational.InExpression;
import net.sf.jsqlparser.expression.operators.relational.ItemsList;
import net.sf.jsqlparser.schema.Column;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 数据权限控制（基于MybatisPlus）
 * mybatis plus 已经实现了DataPermissionInterceptor
 *
 * @author qingyan 2021-07-16
 */
@Slf4j
public class MyDataPermissionHandler implements DataPermissionHandler {

    private DataInterceptor dataInterceptor;

    private String column;


    @Override
    public Expression getSqlSegment(Expression where, String mappedStatementId) {
        DataHandlerEnum lev = getLevel(mappedStatementId);
        switch (lev) {
            case ALL:
                return where;
            case NONE:
                EqualsTo equalsTo = new EqualsTo(new Column("1"), new StringValue("2"));
                return where == null ? equalsTo : new AndExpression(where, equalsTo);
            case ONE:
                EqualsTo equalsTo1 = new EqualsTo(new Column(column), new StringValue(dataInterceptor.one().toString()));
                return where == null ? equalsTo1 : new AndExpression(where, equalsTo1);
            case MANY:
                InExpression in = in(dataInterceptor.many());
                return where == null ? in : new AndExpression(where, in);
        }
        return where;
    }

    private InExpression in(Collection<?> colls) {
        colls.removeIf(Objects::isNull);
        if (colls.isEmpty()) {
            return null;
        }
        ItemsList list = new ExpressionList(colls.stream().map(Object::toString).map(StringValue::new).collect(Collectors.toList()));
        return new InExpression(new Column(column), list);
    }

    public void setDataInterceptor(DataInterceptor interceptor) {
        this.dataInterceptor = interceptor;
    }

    public void setColumn(String column) {
        this.column = column;
    }

    @SneakyThrows
    private DataHandlerEnum getLevel(String mappedStatementId) {
        String className = mappedStatementId.substring(0, mappedStatementId.lastIndexOf("."));
        String methodName = mappedStatementId.substring(mappedStatementId.lastIndexOf(".") + 1);
        final Class<?> cls = Class.forName(className);
        final Method[] methods = cls.getMethods();
        UserInterception anno;
        for (Method method : methods) {
            if (method.getName().equals(methodName) && (anno = method.getAnnotation(UserInterception.class)) != null) {
                if (!StringUtils.isEmpty(anno.conlum())) this.column = anno.conlum();
                return anno.level();
            }
        }
        if ((anno = cls.getAnnotation(UserInterception.class)) != null) {
            if (!StringUtils.isEmpty(anno.conlum())) this.column = anno.conlum();
            return anno.level();
        }
        return DataHandlerEnum.ONE;
    }
}
